package com.wang.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.wang.auth.mapper.SysMenuMapper;
import com.wang.auth.service.SysMenuService;
import com.wang.auth.service.SysRoleMenuService;
import com.wang.auth.utils.MenuHelper;
import com.wang.common.config.exception.CustomException;
import com.wang.model.system.SysMenu;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wang.model.system.SysRoleMenu;
import com.wang.model.system.vo.AssignMenuVo;
import com.wang.model.system.vo.MetaVo;
import com.wang.model.system.vo.RouterVo;
import com.wang.model.wechat.Menu;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.annotation.Resources;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单表 服务实现类
 * </p>
 *
 * @author wang
 * @since 2023-04-17
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    @Resource
    private SysRoleMenuService roleMenuService;

    @Override
    public List<SysMenu> findNodes() {
        List<SysMenu> menuList = this.list();
        return MenuHelper.buildTree(menuList);
    }

    @Override
    public void removeMenuById(Long id) {
        //判断当前菜单下是否有子菜单，如果有就不能删除
        LambdaQueryWrapper<SysMenu> sysMenuLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sysMenuLambdaQueryWrapper.eq(SysMenu::getParentId,id);
        int count = this.count(sysMenuLambdaQueryWrapper);
        if (count > 0) {
            throw new CustomException(201,"菜单不能删除！");
        }
        this.removeById(id);
    }

    @Override
    public List<SysMenu> findSysMenuByRoleId(Long roleId) {
        //1 查询所有菜单- 添加条件 status=1
        LambdaQueryWrapper<SysMenu> sysMenuLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sysMenuLambdaQueryWrapper.eq(SysMenu::getStatus, 1);
        List<SysMenu> sysMenuList = this.list(sysMenuLambdaQueryWrapper);

        //2.根据角色id在角色和菜单维护表中查询当前角色拥有的菜单id集合
        List<Long> menuIds = baseMapper.queryMenuIdsByRoleId(roleId);
        //3.让所有的菜单和当前角色拥有的菜单做比较，如果两者id一样，就吧当前菜单标为选中状态
        for (SysMenu sysMenu : sysMenuList) {
//            for (Long menuId : menuIds) {
//                if (sysMenu.getId().longValue() == menuId.longValue()){
//                    sysMenu.setSelect(true);
//                }
//            }
            //contains相当于上面注释中的循环比较，主要看menuIds中有没有和sysMenu的id一致的菜单id
            if (menuIds.contains(sysMenu.getId())){
                sysMenu.setSelect(true);
            }
        }
        //构建菜单层级关系
        return MenuHelper.buildTree(sysMenuList);
    }

    @Override
    public boolean doAssign(AssignMenuVo assignMenuVo) {
        LambdaQueryWrapper<SysRoleMenu> sysRoleMenuLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sysRoleMenuLambdaQueryWrapper.eq(SysRoleMenu::getRoleId,assignMenuVo.getRoleId());
        roleMenuService.remove(sysRoleMenuLambdaQueryWrapper);

        List<SysRoleMenu> sysRoleMenus = new ArrayList<>();
        for (Long sysMenuId : assignMenuVo.getMenuIdList()) {
            SysRoleMenu sysRoleMenu = new SysRoleMenu();
            sysRoleMenu.setRoleId(assignMenuVo.getRoleId());
            sysRoleMenu.setMenuId(sysMenuId);
            sysRoleMenus.add(sysRoleMenu);
        }
        return roleMenuService.saveBatch(sysRoleMenus);

    }

    @Override
    public List<RouterVo> findUserMenuListByUserId(Long userId) {
        //1.判断是否是管理员，userId=1的是管理员
        //1.1如果是管理员，查询所有菜单列表
        List<SysMenu> menuList = null;
        if (userId == null){
            return null;
        }
        if (userId == 1){
            LambdaQueryWrapper<SysMenu> sysMenuLambdaQueryWrapper = new LambdaQueryWrapper<>();
            sysMenuLambdaQueryWrapper.eq(SysMenu::getStatus,1);
            sysMenuLambdaQueryWrapper.orderByAsc(SysMenu::getSortValue);
            menuList = this.list(sysMenuLambdaQueryWrapper);
        }else {
            //1.2如果不是管理员，根据userId查询可以操作的菜单列表
            //多表联查：用户角色关系表、角色菜单关系表、菜单表
            menuList = baseMapper.findMenuListByUserId(userId);
        }
        //2.把查询出来的数据列表构成框架要求的路由数据结构
        List<SysMenu> sysMenus = MenuHelper.buildTree(menuList);
        return this.buildRouter(sysMenus);
    }


    //构建成框架要求的路由结构
    private List<RouterVo> buildRouter(List<SysMenu> sysMenus) {

        ArrayList<RouterVo> routerVos = new ArrayList<>();
        //获取路由对象集合（路由在数据库中就是菜单表，就是component字段不为空的菜单，
        //顶级菜单和一级菜单的component不为空，所以它两是路由部分，而二级菜单component有可能为空，有可能不为空，不为空的二级菜单又表示为隐藏路由
        //所以routerVos只收集顶级菜单、一级菜单和二级菜单中的隐藏路由
        for (SysMenu sysMenu : sysMenus) {
            RouterVo routerVo = new RouterVo();
            //因为第一次遍历的肯定是顶级菜单，type值为0，不存在隐藏路由，隐藏路由在数据库中只有type为2d按钮可能会有，所以这里直接false
            routerVo.setHidden(false);
            routerVo.setAlwaysShow(false);
            routerVo.setPath(getRouterPath(sysMenu));
            routerVo.setComponent(sysMenu.getComponent());
            routerVo.setMeta(new MetaVo(sysMenu.getName(), sysMenu.getIcon()));
            //获取当前菜单的子菜单
            List<SysMenu> children = sysMenu.getChildren();
            //如果当前菜单为一级菜单，那么一级菜单下面的菜单就是二级菜单，二级菜单是可能有隐藏路由的
            //我们只需要收集隐藏路由作为集合
            if (sysMenu.getType() == 1){
                List<SysMenu> hiddenMenuList = children.stream().filter(
                        item -> StringUtils.isNotBlank(item.getComponent())
                ).collect(Collectors.toList());
                for (SysMenu hiddenMenu : hiddenMenuList) {
                    RouterVo hiddenRouter = new RouterVo();
                    hiddenRouter.setHidden(true);
                    hiddenRouter.setAlwaysShow(false);
                    hiddenRouter.setPath(getRouterPath(hiddenMenu));
                    hiddenRouter.setComponent(hiddenMenu.getComponent());
                    hiddenRouter.setMeta(new MetaVo(hiddenMenu.getName(), hiddenMenu.getIcon()));
                    routerVos.add(hiddenRouter);
                }
            } else {
                //如果当前菜单不是一级菜单，那么他就没有二级菜单，说明他是顶级菜单，判断顶级菜单里是否有一级菜单
                if (!CollectionUtils.isEmpty(children)){
                    if (children.size() > 0){
                        //当你一个路由下面的 children 声明的路由大于1个时，自动会变成嵌套的模式--如组件页面
                        routerVo.setAlwaysShow(true);
                    }
                    //如果顶级菜单里有一级菜单，递归，获取一级菜单和一级菜单里面的属于隐藏路由的二级菜单
                    routerVo.setChildren(buildRouter(children));
                }
            }
            routerVos.add(routerVo);
        }
        return routerVos;
    }



    /**
     * 获取路由地址
     *
     * @param menu 菜单信息
     * @return 路由地址
     */
    public String getRouterPath(SysMenu menu) {
        String routerPath = "/" + menu.getPath();
        if(menu.getParentId().intValue() != 0) {
            routerPath = menu.getPath();
        }
        return routerPath;
    }
    @Override
    public List<String> findUserPermsByUserId(Long userId) {
        //1.判断是否是管理员，userId=1的是管理员
        //1.1如果是管理员，查询所有菜单列表
        List<SysMenu> menuList = null;
        if (userId == null){
            return null;
        }
        if (userId == 1){
            LambdaQueryWrapper<SysMenu> sysMenuLambdaQueryWrapper = new LambdaQueryWrapper<>();
            sysMenuLambdaQueryWrapper.eq(SysMenu::getStatus,1);
            menuList = this.list(sysMenuLambdaQueryWrapper);
        }else {
            //1.2如果不是管理员，根据userId查询可以操作的菜单列表
            //多表联查：用户角色关系表、角色菜单关系表、菜单表
            menuList = baseMapper.findMenuListByUserId(userId);
        }
        //3 从查询出来的数据里面，获取可以操作按钮值的list集合，返回
        return menuList.stream().filter(item -> item.getType() == 2).map(SysMenu::getPerms).collect(Collectors.toList());
    }
}
